package com.klm.easymq.core;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.UUID;

/**
 * 幂等键生成器
 * 支持SpEL表达式解析，用于生成幂等控制键
 */
@Slf4j
@Component
public class IdempotentKeyGenerator {
    
    private final ExpressionParser parser = new SpelExpressionParser();
    private final DefaultParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
    
    public IdempotentKeyGenerator() {
        // 默认构造函数
    }
    
    /**
     * 生成幂等键
     * @param message 消息对象
     * @param topic 主题
     * @return 幂等键
     */
    public String generateKey(Object message, String topic) {
        try {
            // 创建表达式上下文
            StandardEvaluationContext context = new StandardEvaluationContext();
            context.setVariable("message", message);
            context.setVariable("topic", topic);
            
            // 使用默认表达式
            String keyExpression = "#message.id != null ? #message.id : #message.hashCode()";
            
            // 解析表达式
            Expression expression = parser.parseExpression(keyExpression);
            Object result = expression.getValue(context);
            
            if (result == null) {
                // 如果表达式解析失败，使用默认键
                return generateDefaultKey(message, topic);
            }
            
            return result.toString();
            
        } catch (Exception e) {
            log.warn("Failed to generate idempotent key, fallback to default key", e);
            return generateDefaultKey(message, topic);
        }
    }
    
    /**
     * 根据表达式和方法参数生成幂等键
     * @param expression SpEL表达式
     * @param method 方法
     * @param args 方法参数
     * @return 幂等键
     */
    public String generateKey(String expression, Method method, Object[] args) {
        try {
            String[] parameterNames = parameterNameDiscoverer.getParameterNames(method);
            EvaluationContext context = new StandardEvaluationContext();
            
            if (parameterNames != null) {
                for (int i = 0; i < parameterNames.length && i < args.length; i++) {
                    context.setVariable(parameterNames[i], args[i]);
                }
            }
            
            Expression exp = parser.parseExpression(expression);
            Object result = exp.getValue(context);
            return result != null ? result.toString() : UUID.randomUUID().toString();
            
        } catch (Exception e) {
            log.warn("生成幂等键失败，使用随机UUID: expression={}", expression, e);
            return UUID.randomUUID().toString();
        }
    }
    
    /**
     * 生成默认幂等键
     * @param message 消息对象
     * @param topic 主题
     * @return 默认幂等键
     */
    private String generateDefaultKey(Object message, String topic) {
        // 使用消息的hashCode和主题生成默认键
        int messageHash = message != null ? message.hashCode() : 0;
        return topic + ":" + messageHash;
    }
} 